package com.kds.changzhou.utility;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Stack;

/**
 * @author 孔德嵩
 * 创建日期 2023/12/12
 */
@Component
@Slf4j
public class ExpressionEvaluation {

    /**
     * 对形如：String expression = "12.8+5.65*2+1.8*45";的表达式进行计算
     *
     * @param expression
     * @return
     */
    public double evaluateExpression(StringBuffer expression) {

        log.debug("待计算的表达式：{}", expression);

        Stack<Double> numbers = new Stack<>();
        Stack<Character> operators = new Stack<>();

        for (int i = 0; i < expression.length(); i++) {
            char c = expression.charAt(i);
            if (Character.isDigit(c) || c == '.') {
                StringBuilder num = new StringBuilder();
                while (i < expression.length() && (Character.isDigit(expression.charAt(i)) || expression.charAt(i) == '.')) {
                    num.append(expression.charAt(i));
                    i++;
                }
                i--;
                numbers.push(Double.parseDouble(num.toString()));
            } else if (c == '+' || c == '-' || c == '*' || c == '/') {
                while (!operators.isEmpty() && hasPrecedence(c, operators.peek())) {
                    applyOperation(numbers, operators);
                }
                operators.push(c);
            }
        }

        while (!operators.isEmpty()) {
            applyOperation(numbers, operators);
        }

        return numbers.pop();
    }

    private boolean hasPrecedence(char op1, char op2) {
        return (op2 == '*' || op2 == '/') || (op1 == '+' || op1 == '-');
    }

    private void applyOperation(Stack<Double> numbers, Stack<Character> operators) {
        char op = operators.pop();
        double num2 = numbers.pop();
        double num1 = numbers.pop();
        double result = 0.0;
        switch (op) {
            case '+':
                result = num1 + num2;
                break;
            case '-':
                result = num1 - num2;
                break;
            case '*':
                result = num1 * num2;
                break;
            case '/':
                result = num1 / num2;
                break;
        }
        numbers.push(result);
    }
}
